Inside Macintosh: Imaging with QuickDraw

Previous | Chapter Top | Chapter Contents | Next

Zooming Windows on Multiscreen Systems

The zoom box in the upper-right corner of the standard document window allows the user to alternate quickly between two window positions and sizes: the user state and the standard state.

The user state is the window size and location established by the user. If your application does not supply an initial user state, the user state is simply the size and location of the window when it was created, until the user resizes it.

The standard state is the window size and location that your application considers most convenient, considering the function of the document and the screen space available. In a word-processing application, for example, a standard-state window might show a full page, if possible, or a page of full width and as much length as fits on the screen. If the user changes the page size with the Page Setup command, the application might adjust the standard state to reflect the new page size. If your application does not define a standard state, the Window Manager automatically sets the standard state to the entire gray region on the main screen, minus a three-pixel border on all sides. (See Macintosh Human Interface Guidelines for a detailed description of how your application determines where to open and zoom windows.) The user cannot change a window's standard state . (The user and standard states are stored in a data structure of type WStateData whose handle appears in the dataHandle field of the window record.)

Listing 3 illustrates an application-defined procedure, DoZoomWindow , which an application might call when the user clicks the zoom box. Because the user might have moved the window to a different screen since it was last zoomed, the procedure first determines which screen contains the largest area of the window and then calculates the ideal window size for that screen before zooming the window.

The screen calculations in the DoZoomWindow procedure compare GDevice records stored in the device list. (If Color QuickDraw is not available, DoZoomWindow assumes that it's running on a computer with a single screen.)

Listing 3 Zooming a window

PROCEDURE DoZoomWindow (thisWindow: windowPtr; zoomInOrOut: Integer);
VAR
    gdNthDevice, gdZoomOnThisDevice:            GDHandle;
    savePort:                                   GrafPtr;
    windRect, zoomRect, theSect:                Rect;
    sectArea, greatestArea:                     LongInt;
    wTitleHeight:                               Integer;
    sectFlag:                                   Boolean;
BEGIN
    GetPort(savePort);
    SetPort(thisWindow);
    EraseRect(thisWindow^.portRect);                {erase to avoid flicker}
    IF zoomInOrOut = inZoomOut THEN                 {zooming to standard state}
    BEGIN
        IF NOT gColorQDAvailable THEN               {assume a single screen and }
        BEGIN                                       { set standard state to full screen}
            zoomRect := screenBits.bounds;
            InsetRect(zoomRect, 4, 4);
            WStateDataHandle(WindowPeek(thisWindow)^.dataHandle)^^.stdState
                                                                                    := zoomRect;
        END
        ELSE                            {locate window on available screens}
        BEGIN
            windRect := thisWindow^.portRect;
            LocalToGlobal(windRect.topLeft);                {convert to global coordinates}
            LocalToGlobal(windRect.botRight);
            {calculate height of window's title bar}
            wTitleHeight := windRect.top - 1 -
                             WindowPeek(thisWindow)^.strucRgn^^.rgnBBox.top;
            windRect.top := windRect.top - wTitleHeight;
            gdNthDevice := GetDeviceList;               {get the first screen}
            greatestArea := 0;                  {initialize area to 0}
            {check window against all gdRects in gDevice list and remember }
            { which gdRect contains largest area of window}
            WHILE gdNthDevice <> NIL DO
            IF TestDeviceAttribute(gdNthDevice, screenDevice) THEN
                IF TestDeviceAttribute(gdNthDevice, screenActive) THEN
                BEGIN
                    {The SectRect function calculates the intersection }
                    { of the window rectangle and this GDevice's boundary }
                    { rectangle and returns TRUE if the rectangles intersect, }
                    { FALSE if they don't.}
                    sectFlag := SectRect(windRect, gdNthDevice^^.gdRect,
                                                 theSect);
                    {determine which screen holds greatest window area}
                    {first, calculate area of rectangle on current screen}
                    WITH theSect DO         
                        sectArea := LongInt(right - left) * (bottom - top);
                    IF sectArea > greatestArea THEN
                    BEGIN
                        greatestArea := sectArea;           {set greatest area so far}
                        gdZoomOnThisDevice := gdNthDevice;              {set zoom device}
                    END;
                    gdNthDevice := GetNextDevice(gdNthDevice);                  {get next }
                END;    {of WHILE}                                              { GDevice record}
            {if gdZoomOnThisDevice is on main device, allow for menu bar height}
            IF gdZoomOnThisDevice = GetMainDevice THEN
                wTitleHeight := wTitleHeight + GetMBarHeight;
            WITH gdZoomOnThisDevice^^.gdRect DO                 {create the zoom rectangle}
            BEGIN
                {set the zoom rectangle to the full screen, minus window title }
                { height (and menu bar height if necessary), inset by 3 pixels}
                SetRect(zoomRect, left + 3, top + wTitleHeight + 3,
                         right - 3, bottom - 3);
                {If your application has a different "most useful" standard }
                { state, then size the zoom window accordingly.}
                
                {set up the WStateData record for this window}
                WStateDataHandle(WindowPeek(thisWindow)^.dataHandle)^^.stdState
                                                                                     := zoomRect;
            END;
        END;
    END; {of inZoomOut}
    {if zoomInOrOut = inZoomIn, just let ZoomWindow zoom to user state}
    {zoom the window frame}
    ZoomWindow(thisWindow, zoomInOrOut, (thisWindow = FrontWindow));
    MyResizeWindow(thisWindow);             {application-defined window-sizing routine}
    SetPort(savePort);
END; (of DoZoomWindow)

If the user is zooming the window to the standard state, DoZoomWindow calculates a new standard size and location based on the application's own considerations, the current location of the window, and the available screens. The DoZoomWindow procedure always places the standard state on the screen where the window is currently displayed or, if the window spans screens, on the screen containing the largest area of the window.

Listing 3 uses the QuickDraw routines GetDeviceList , TestDeviceAttribute , GetNextDevice , SectRect , and GetMainDevice to examine characteristics of the available screens as stored in GDevice records. Most of the code in Listing 3 is devoted to determining which screen should display the window in the standard state.

Never use the bounds field of a PixMap record to determine the size of the screen; instead use the value of the gdRect field of the GDevice record for the screen, as shown in Listing 3 .

After calculating the standard state, if necessary, DoZoomWindow calls the ZoomWindow procedure to redraw the window frame in the new size and location and then calls the application-defined procedure MyResizeWindow to redraw the window's content region. For more information on zooming and resizing windows, see the chapter "Window Manager" in Inside Macintosh: Macintosh Toolbox Essentials .


© 1997 Apple Computer, Inc.

Previous | Chapter Top | Chapter Contents | Next